package com.swotxu.oldwebproject.session.utils;

import com.swotxu.oldwebproject.redis.RedisManager;
import com.swotxu.oldwebproject.redis.connection.IRedisConnection;
import com.swotxu.oldwebproject.redis.utils.RedisPropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.lang.management.ManagementFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.Set;
import java.util.UUID;

/**
 * RedisSession
 *  针对session的相关操作
 *
 * @Date: 2020/1/9 15:39
 * @Author: xu.hai
 */
public class RedisSessionUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisSessionUtil.class);

    private static final int SESSION_ID_BYTES = 20;
    private static final String ALGORITHM = "MD5";
    private static IRedisConnection redisConnection = RedisManager.getIRedisConnection();

    public static final String SESSION_PREFIX = RedisPropertiesUtil.getSystemName()+ ":session:";
    public static final String SESSION_ATTR_PREFIX = "sessionAttr:";
    public static final String SESSION_TOKEN = "RS_TOKEN";

    public static final String SERVLETCONTEXT = RedisPropertiesUtil.getSystemName()+ ":servletContext:";
    /** 服务器唯一ID */
    public static final String SERVER_ID_CARD_HEARD = RedisPropertiesUtil.getSystemName()+ ":serverIdCard:";
    public static final String SERVER_ID_CARD = UUID.randomUUID().toString().replace("-", "");
    /** 服务器唯一ID,默认过期时间 30s */
    public static final int SERVER_DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 30;
    /** 默认 SESSION 过期时间 */
    public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800;
    /** 配置 SESSION 过期时间 */
    public static final int SESSION_INACTIVE_INTERVAL = RedisPropertiesUtil.getRedisCofig().getSessionInactiveInterval();

    /**
     * 生成 sessionId
     * @return
     */
    public static synchronized String generateSessionId() {
        Random random = new SecureRandom();
        byte bytes[] = new byte[SESSION_ID_BYTES];
        random.nextBytes(bytes);
        long currentTime = System.currentTimeMillis();
        String pid = ManagementFactory.getRuntimeMXBean().getName();
        StringBuffer sb = new StringBuffer(new String(bytes));
        sb.append(currentTime).append(pid);
        bytes = sb.toString().getBytes();
        bytes = getDigest().digest(bytes);
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
            byte b2 = (byte) (bytes[i] & 0x0f);
            if (b1 < 10) {
                result.append((char) ('0' + b1));
            } else {
                result.append((char) ('A' + (b1 - 10)));
            }
            if (b2 < 10) {
                result.append((char) ('0' + b2));
            } else {
                result.append((char) ('A' + (b2 - 10)));
            }
        }
        return result.toString();
    }

    public static String getSessionKey(String token) {
        return SESSION_PREFIX.concat(token);
    }

    public static String getSessionAttrField(String field) {
        return SESSION_ATTR_PREFIX.concat(field);
    }

    public static int getExpire() {
        return SESSION_INACTIVE_INTERVAL > 0 ? SESSION_INACTIVE_INTERVAL : DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;
    }

    private static MessageDigest getDigest() {
        try {
            MessageDigest md = MessageDigest.getInstance(ALGORITHM);
            return md;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 向 redis中注册当前服务器。
     * 过期时间 30s，用于标识当前服务器在线
     */
    public static void registrationCurrentServer(){
        String serverKey = SERVER_ID_CARD_HEARD + SERVER_ID_CARD;
        LOGGER.debug("registration Server: " + serverKey);
        redisConnection.set(serverKey, 1);
        redisConnection.expire(serverKey, SERVER_DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
    }
    /**
     * 从 redis中注销当前服务器。
     */
    public static void logoutCurrentServer(){
        String serverKey = SERVER_ID_CARD_HEARD + SERVER_ID_CARD;
        LOGGER.info("logout Server: " + serverKey);
        redisConnection.del(serverKey);
    }

    /**
     * 检查redis中存活的服务器
     * 若无存活服务器，或仅自己存活，返回true，否则返回false
     * @return
     */
    public static boolean checkOnlineServer(){
        String serverKey = SERVER_ID_CARD_HEARD + SERVER_ID_CARD;
        String serverAllKey = SERVER_ID_CARD_HEARD + "*";
        Set<String> servers = redisConnection.keys(serverAllKey);

        LOGGER.info("Current live server: " + servers);
        return CollectionUtils.isEmpty(servers) || (servers.size() == 1 && servers.contains(serverKey));
    }

    /**
     * 批量删除 redis中 key
     * @param regexKey 如： cbm:session:*
     */
    public static void delAllByRegexKey(String regexKey){
        Set<String> keySet = redisConnection.keys(regexKey);
        if (!CollectionUtils.isEmpty(keySet)) {
            String[] keys = keySet.toArray(new String[keySet.size()]);
            redisConnection.del(keys);
        }
    }

}
